package repeater
//
//import (
//    "github.com/boltdb/bolt"
//    "fmt"
//    "time"
//)
//
//type BoltDB struct {
//    workingDB       *bolt.DB
//    workingFileName string
//    workingData     map[string]DataSet
//    workingOffset   map[string]int64
//    desc            *DBDesc
//}
//
//func (db *BoltDB) Prepare(k CacheKey, m ReportMetric, v float64) {
//    db.desc.handle(k.Ip, k.Offset)
//    if _, ok := db.workingData[k.Ip]; !ok {
//        db.workingData[k.Ip] = make(map[ReportMetric]Value)
//    }
//    db.workingData[k.Ip].Add(m, v)
//    if db.workingOffset[k.Ip] < k.Offset {
//        db.workingOffset[k.Ip] = k.Offset
//    }
//}
//
//func (db *BoltDB) Commit() error {
//    if db.workingDB == nil {
//        return fmt.Errorf("boltdb not init")
//    }
//    tx, err := db.workingDB.Begin(true)
//    if err != nil {
//        return err
//    }
//    for Ip, value := range db.workingData {
//        key := CacheKey{Ip, 0, db.workingOffset[Ip]}
//        k1, k2, err := key.toBytes2()
//        if err != nil {
//            return err
//        }
//        v, err := value.toBytes()
//        if err != nil {
//            return err
//        }
//        b, err := tx.CreateBucketIfNotExists(k1)
//        if err != nil {
//            return err
//        }
//        if err = b.Put(k2, v); err != nil {
//            return err
//        }
//    }
//    b, err := tx.CreateBucketIfNotExists(([]byte("meta")))
//    if err != nil {
//        return err
//    }
//    k, v, err := db.desc.KeyValue()
//    if err != nil {
//        return err
//    }
//    err = b.Put(k, v)
//    if err != nil {
//        return err
//    }
//    err = tx.Commit()
//    if err != nil {
//        return err
//    }
//    db.workingData = make(map[string]DataSet)
//    db.workingOffset = make(map[string]int64)
//    return nil
//}
//func (db *BoltDB) ShouldClose(limit int64) bool {
//    if db.desc.LastWriteTime == 0 {
//        return db.desc.InitialTime-db.desc.LastWriteTime > limit
//    }
//    return time.Now().Unix()-db.desc.LastWriteTime > limit
//}
//
//func (db *BoltDB) Close() error {
//    if err := db.workingDB.Sync(); err != nil {
//        return err
//    }
//    if err := db.workingDB.Close(); err != nil {
//        return err
//    }
//    db.workingDB = nil
//    return nil
//}
//
//func (db *BoltDB) Init(fn string) (err error) {
//    if db.workingDB != nil {
//        return fmt.Errorf("unfinished bolt %v", db.workingDB)
//    }
//    db.workingDB, err = bolt.Open(fn, 0644, nil)
//    if err != nil {
//        return err
//    }
//    db.workingDB.View(func(tx *bolt.Tx) error {
//        b := tx.Bucket([]byte("meta")).Get([]byte(DESCNAME))
//        db.desc = NewDBMeta(b)
//        return nil
//    })
//    db.workingFileName = fn
//    db.workingData = make(map[string]DataSet)
//    db.workingOffset = make(map[string]int64)
//    return nil
//}
//
//func (db *BoltDB) Clean(keys []CacheKey) error {
//    return db.workingDB.Update(func(tx *bolt.Tx) error {
//        for _, key := range keys {
//            k1, _, err := key.toBytes2()
//            if err != nil {
//                return err
//            }
//            if err := tx.DeleteBucket(k1); err != nil {
//                return err
//            }
//        }
//        return tx.Commit()
//    })
//}
//
//func (db *BoltDB) Flush(cd *CacheSet, offset int64) error {
//    log.Infof("boltdb try to flush %d points, at offset %d ", cd.uncommitedSize(), offset)
//    t := time.Now().UnixNano()
//    var count int64
//    defer func() {
//        cost := time.Now().UnixNano() - t
//        log.Infof("boltdb flushed %d costs %d ms", count, int(cost/1000/1000))
//    }()
//    if db.workingDB == nil {
//        return fmt.Errorf("boltdb not init")
//    }
//    tx, err := db.workingDB.Begin(true)
//    if err != nil {
//        return err
//    }
//    for rk, ds := range cd.uncommitted {
//        rk.Offset = offset
//        k1, k2, err := rk.toBytes2()
//        if err != nil {
//            return err
//        }
//        b, err := tx.CreateBucketIfNotExists(k1)
//        if err != nil {
//            return err
//        }
//        v, err := ds.toBytes()
//        if err != nil {
//            return err
//        }
//        b.Put(k2, v)
//        count += ds.size()
//    }
//    if err = tx.Commit(); err != nil {
//        return err
//    }
//    cd.markCommited(offset)
//    return nil
//}
//
//func (db *BoltDB) Load(c *CacheSet) (err error) {
//    if db.workingDB == nil {
//        return fmt.Errorf("boltdb not init")
//    }
//    log.Infof("start load from bolt cache")
//    var count int64
//    t := time.Now().UnixNano() / 1000 / 1000
//    defer func() {
//        t2 := time.Now().UnixNano() / 1000 / 1000
//        log.Infof("loaded: %d points from bolt cache, in %d ms", count, int(t2-t))
//    }()
//    return db.workingDB.View(func(tx *bolt.Tx) error {
//        return tx.ForEach(func(k []byte, b *bolt.Bucket) error {
//            return b.ForEach(func(o, v []byte) error {
//                i, err := c.addRaw(k, o, v)
//                count += i
//                return err
//            })
//        })
//    })
//}
